package utils

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"golang.org/x/crypto/bcrypt"
	"log/slog"
	"os"
)

func init() {
	if secret := os.Getenv("SECRET"); secret == "" && len(secret)%16 != 0 {
		slog.Error("env SECRET should not be empty, and length of secret must be 16, 24 or 32.")
		os.Exit(1)
	}
}

// EncryptAES aes加密
func EncryptAES(data string) (string, error) {
	src := []byte(data)
	secretKey := os.Getenv("SECRET")
	// 1. 创建并返回一个使用AES算法的cipher.Block接口
	block, err := aes.NewCipher([]byte(secretKey))
	if err != nil {
		return "", err
	}
	bs := block.BlockSize()
	// 2. 填充数据
	src = paddingText(src, bs)
	// 3. 创建一个密码分组为链接模式的, 底层使用AES加密的BlockMode接口
	blockMode := cipher.NewCBCEncrypter(block, []byte(secretKey))
	// 4. 数据加密
	blockMode.CryptBlocks(src, src)
	fmt.Println(hex.EncodeToString(src))
	return hex.EncodeToString(src), nil
}

// DecryptAES aes解密
func DecryptAES(data string) (string, error) {
	src, err := hex.DecodeString(data)
	secretKey := os.Getenv("SECRET")
	//1. 创建并返回一个使用AES算法的cipher.Block接口
	block, err := aes.NewCipher([]byte(secretKey))
	if err != nil {
		return "", err
	}
	//2. 创建一个密码分组为链接模式的, 底层使用AES解密的BlockMode接口
	blockMode := cipher.NewCBCDecrypter(block, []byte(secretKey))
	//3. 数据块解密
	blockMode.CryptBlocks(src, src)
	//4. 去掉最后一组的填充数据
	src = unPaddingText(src)
	return string(src), nil
}
func paddingText(src []byte, blockSize int) []byte {
	// 1. 求出最后一个分组要填充多少个字节
	padding := blockSize - len(src)%blockSize
	// 2. 创建新的切片, 切片的字节数为padding, 并初始化, 每个字节的值为padding
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	// 3. 将创建出的新切片和原始数据进行连接
	newText := append(src, padText...)
	// 4. 返回新的字符串
	return newText
}

// 删除末尾填充的字节
func unPaddingText(src []byte) []byte {
	// 1. 求出要处理的切片的长度
	length := len(src)
	// 2. 取出最后一个字符, 得到其整型值
	number := int(src[length-1])
	// 3. 将切片末尾的number个字节删除
	newText := src[:length-number]
	return newText
}

// EncodeBase64 base64加密
func EncodeBase64(data []byte) string {
	return base64.StdEncoding.EncodeToString(data)
}

// DecodeBase64 base64解密
func DecodeBase64(data string) ([]byte, error) {
	bts, err := base64.StdEncoding.DecodeString(data)
	if err != nil {
		return nil, err
	}
	return bts, nil
}

// HashPassword 获取密码的hash值
func HashPassword(password string) (string, error) {
	bts, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return "", err
	}
	return string(bts), nil
}

// CheckPassword 检测密码是否正确
func CheckPassword(hashPassword, password string) error {
	return bcrypt.CompareHashAndPassword([]byte(hashPassword), []byte(password))
}
